//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   CartMesh.i.hh
 * \author Jeremy Roberts
 * \date   Jul 8, 2011
 * \brief  Inline definitions for Mesh classes
 * \note   Copyright (C) 2011 Jeremy Roberts. 
 */
//---------------------------------------------------------------------------//
// $Rev:: 121                                           $:Rev of last commit
// $Author:: j.alyn.roberts@gmail.com                   $:Author of last commit
// $Date:: 2011-08-06 01:04:32 +0000 (Sat, 06 Aug 2011) $:Date of last commit
//---------------------------------------------------------------------------//


#ifndef CARTMESH_I_HH_
#define CARTMESH_I_HH_

namespace slabtran
{

//---------------------------------------------------------------------------//
/*!
 * \brief Return number of cells in a given direction.
 *
 * \param  dimension   x, y, or z
 * \return number of cells in dimension.
 */
template <class D>
inline int Mesh<D>::number_cells_direction(int dimension) const
{
  Require (dimension < d_dimension);
  return d_number_cells_direction[dimension];
};

//! Specialization for 1d.
template <>
inline int Mesh<_1D>::number_cells_direction(int dimension) const
{
  Require (dimension < d_dimension);
  return d_number_cells;
};

//---------------------------------------------------------------------------//
/*!
 * \brief Convert an (i,j,k) index to a cardinal mesh index.
 *
 * \return cardinal mesh index.
 */
template <class D>
inline int Mesh<D>::convert(int i, int j, int k) const
{
    Require (i >= 0 && i < d_number_cells_direction[I]);
    Require (j >= 0 && j < d_number_cells_direction[J]);
    Require (k >= 0 && k < d_number_cells_direction[K]);
    return i + j * d_number_cells_direction[I] +
           k * d_number_cells_direction[I] * d_number_cells_direction[J];
}

//! Specialization for 1d.
template <>
inline int Mesh<_2D>::convert(int i, int j, int k) const
{
  Require(i >= 0 && i < d_number_cells_direction[I]);
  Require(j >= 0 && j < d_number_cells_direction[J]);
  return i + j * d_number_cells_direction[I];
}
template <>
inline int Mesh<_1D>::convert(int i, int j, int k) const
{
  Require(i >= 0 && i < d_number_cells_direction);
  return i;
}

//---------------------------------------------------------------------------//
/*!
 * \brief Return the width of a cell in the specified direction.
 *
 * \param ijk \e (i,j,k) index
 * \param dimension \e (I,J,K) [or \e (X,Y,Z) ] direction
 *
 * \return cell width in \e (X,Y,Z) dimension in cm
 */
template <class D>
inline double Mesh<D>::width(int ijk, int dimension) const
{
    Require (dimension < d_dimension);
    Require (ijk < d_number_cells_direction[dimension]);
    Ensure (d_width[dimension][ijk] > 0.0);
    Ensure (util::soft_equiv(
            d_width[dimension][ijk],
            (d_edges[dimension][ijk + 1]-d_edges[dimension][ijk])));  // why this check?
    return d_width[dimension][ijk];
}

//! Specialization for 1d.
template <>
inline double Mesh<_1D>::width(int ijk, int dimension) const
{
    Require (dimension < d_dimension);  // i.e. = 0
    Require (ijk < d_number_cells);
    Ensure (d_width[ijk] > 0.0);
    Ensure (util::soft_equiv(d_width[ijk],(d_edges[ijk + 1]-d_edges[ijk])));  // why this check?
    return d_width[ijk];
}

//---------------------------------------------------------------------------//
/*!
 * \brief Return the inverse width of a cell in the specified direction.
 *
 * \param ijk \e (i,j,k) index
 * \param dimension \e (I,J,K) [or \e (X,Y,Z) ] direction
 *
 * \return inverse cell width in \e (X,Y,Z) dimension in cm\f$^{-1}\f$
 */
template <class D>
inline double Mesh<D>::inv_width(int ijk, int dimension) const
{
    Require (dimension < d_dimension);
    Require (ijk < d_number_cells_direction[dimension]);
    Ensure (d_width[dimension][ijk] > 0.0);
    return d_inv_width[dimension][ijk];
}

//! Specialization for 1d
template <>
inline double Mesh<_1D>::inv_width(int ijk, int dimension) const
{
    Require (dimension < d_dimension);
    Require (ijk < d_number_cells);
    Ensure (d_width[ijk] > 0.0);
    return d_inv_width[ijk];
}

//---------------------------------------------------------------------------//
/*!
 * \brief Return the center of a cell in the specified direction.
 *
 * \param ijk \e (i,j,k) index
 * \param dimension \e (I,J,K) [or \e (X,Y,Z) ] direction
 *
 * \return cell center in \e (X,Y,Z) dimension in cm
 */
template <class D>
inline double Mesh<D>::center(int ijk, int dimension) const
{
    Require (dimension < d_dimension);
    Require (ijk < d_number_cells_direction[dimension]);
    return 0.5 * (d_edges[dimension][ijk + 1] + d_edges[dimension][ijk]);
}

//! Specialization for 1d
template <>
inline double Mesh<_1D>::center(int ijk, int dimension) const
{
    Require (dimension < d_dimension);
    Require (ijk < d_number_cells);
    return 0.5 * (d_edges[ijk + 1] + d_edges[ijk]);
}

template <class D>
void Mesh<D>::set_cell_id(const int key, const Vec_Id &value)
{
  Require(d_cell_ids.find(key) == d_cell_ids.end()); // can't already have it
  Require(value.size() == d_number_cells); // id for every cell
  d_cell_ids.insert(Mesh<D>::Cell_Ids_Value_Type(key, value));
  return;
}

template <class D>
const typename Mesh<D>::Vec_Id& Mesh<D>::get_cell_id(const int key)
{
  Require(!d_cell_ids.empty());
  Require(d_cell_ids.find(key) != d_cell_ids.end());
  const Vec_Id &v = (d_cell_ids.find(key))->second;
  Ensure(v.size() == d_number_cells);
  return v;
}

template <class D>
inline int Mesh<D>::region_index(int i) const
{
	Require (i < d_number_cells);
	return d_region_index[i];
}


} // end namespace slabtran

#endif /* CARTMESH_I_HH_ */

//---------------------------------------------------------------------------//
//              end of CartMesh.i.hh
//---------------------------------------------------------------------------//
